﻿using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;
using System.Drawing;

namespace DotNet.Common
{
    /// <summary>
    /// 曲线控件
    /// </summary>
    public partial class WaveBox : Control
    {
        WaveAxis _axis;
        WaveCurveGroup _curveGroup = new WaveCurveGroup();
        bool _mouseEnterFlag;
        bool _autoRange;
        Keys _cursorDecrease, _cursorIncrease, _zoomIn, _zoomOut;
        int _captureDownX;
        DoubleRange _captureRangeX = new DoubleRange();

        /// <summary>
        /// 快捷键：光标减小一格
        /// </summary>
        public Keys CursorDecrease
        {
            get { return _cursorDecrease; }
            set { _cursorDecrease = value; }
        }

        /// <summary>
        /// 快捷键：光标增加一格
        /// </summary>
        public Keys CursorIncrease
        {
            get { return _cursorIncrease; }
            set { _cursorIncrease = value; }
        }

        /// <summary>
        /// 快捷键：放大
        /// </summary>
        public Keys ZoomIn
        {
            get { return _zoomIn; }
            set { _zoomIn = value; }
        }

        /// <summary>
        /// 快捷键：缩小
        /// </summary>
        public Keys ZoomOut
        {
            get { return _zoomOut; }
            set { _zoomOut = value; }
        }

        public bool Smooth
        {
            get { return _curveGroup.Smooth; }
            set { _curveGroup.Smooth = value; }
        }

        public WaveAxis Axis
        {
            get { return _axis; }
        }

        public WaveCurveGroup CurveGroup
        {
            get { return _curveGroup; }
        }

        public bool AutoRange
        {
            get { return _autoRange; }
            set { _autoRange = value; }
        }

        public WaveBox()
        {
            InitializeComponent();
            InitializeCustom();
        }

        public WaveBox(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
            InitializeCustom();
        }

        private void InitializeCustom()
        {
            _axis = new WaveAxis(base.Handle);

            this.BackColor = SystemColors.WindowFrame;
            this.TabStop = false;
            _mouseEnterFlag = false;
            _autoRange = true;
            _cursorDecrease = Keys.A;
            _cursorIncrease = Keys.D;
            _zoomIn = Keys.W;
            _zoomOut = Keys.S;

            this.Resize += new EventHandler(WaveBox_Resize);
            this.Paint += new PaintEventHandler(WaveBox_Paint);

            this.MouseDown += new MouseEventHandler(WaveBox_MouseDown);
            this.MouseUp += new MouseEventHandler(WaveBox_MouseUp);
            this.MouseEnter += new EventHandler(WaveBox_MouseEnter);
            this.MouseLeave += new EventHandler(WaveBox_MouseLeave);
            this.MouseMove += new MouseEventHandler(WaveBox_MouseMove);
            this.MouseWheel += new MouseEventHandler(WaveBox_MouseWheel);

            this.KeyDown += new KeyEventHandler(WaveBox_KeyDown);

            this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
            this.UpdateStyles();

            _curveGroup.OnResize += new VoidInvoker(_curveGroup_OnResize);
            _axis.OnUpdateXStartOffset += new IntInvoker(_axis_OnUpdateXStartOffset);
        }

        void WaveBox_KeyDown(object sender, KeyEventArgs e)
        {
            if(e.KeyData == _cursorDecrease)
            {
                UpdateCursorShow(_curveGroup.CursorXPoint - 1);     // 左移
            }
            else if (e.KeyData == _cursorIncrease)
            {
                UpdateCursorShow(_curveGroup.CursorXPoint + 1); // 右移
            }
            else if (e.KeyData == _zoomIn)
            {
                Zoom(true); // 放大
            }
            else if (e.KeyData == _zoomOut)
            {
                Zoom(false);// 缩小
            }
            else
            {
                return;
            }

            e.Handled = true;
        }

        void WaveBox_MouseDown(object sender, MouseEventArgs e)
        {
            if(e.Button == MouseButtons.Right)
            {
                this.Capture = true;
                this.Cursor = Cursors.Hand;
                _captureDownX = e.X;
                _captureRangeX.CopyFrom(_axis.XRange);
            }
        }

        void WaveBox_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                this.Capture = false;
                this.Cursor = Cursors.Default;
            }
        }

        void WaveBox_MouseEnter(object sender, EventArgs e)
        {
            this.Focus();
            _mouseEnterFlag = true;
        }

        void WaveBox_MouseLeave(object sender, EventArgs e)
        {
            _mouseEnterFlag = false;
        }

        void WaveBox_MouseWheel(object sender, MouseEventArgs e)
        {
            if (_mouseEnterFlag)
                Zoom(e.Delta > 0);
        }

        private void WaveBox_MouseMove(object sender, MouseEventArgs e)
        {
            if (this.Capture && e.Button == MouseButtons.Right)
            {
                double min, max;
                _curveGroup.GetCurveXRange(out min, out max);
                if (!(min == _axis.XRange.Min && max == _axis.XRange.Max))
                {
                    _axis.XRange.CopyFrom(_captureRangeX);
                    _axis.XRange.Shift(_captureRangeX.Range * (_captureDownX - e.X) / _curveGroup.Width);
                    _axis.XRange.Adjust(min, max);

                    _axis.UpdateXRange();
                    _curveGroup.UpdateShow(_axis.XRange, _axis.YRange);
                }
            }
            UpdateCursorShow(e.X);
        }

        /// <summary>
        /// 缩放
        /// </summary>
        /// <param name="zoomFlag">True：放大 False：缩小</param>
        private void Zoom(bool zoomInFlag)
        {
            if (this.Capture)
                return;

            if (!_axis.XRange.Contain(_curveGroup.CursorXValue))
                return;

            double min,max;
            if (!_curveGroup.GetCurveXRange(out min, out max))
                return;

            if (zoomInFlag)    // 放大
            {
                _axis.XRange.Min += (_curveGroup.CursorXValue - _axis.XRange.Min) / 8;
                _axis.XRange.Max += (_curveGroup.CursorXValue - _axis.XRange.Max) / 8;
            }
            else               // 缩小
            {
                if (_axis.XRange.Min <= min && _axis.XRange.Max >= max)
                    return;

                _axis.XRange.Min -= (_curveGroup.CursorXValue - _axis.XRange.Min) / 7;
                _axis.XRange.Max -= (_curveGroup.CursorXValue - _axis.XRange.Max) / 7;

                _axis.XRange.Adjust(min, max);
            }

            _axis.UpdateXRange();
            UpdateCursor(_curveGroup.CursorXPoint);
            UpdateCurveShow();
        }

        public void UpdateShow()
        {
            if (_autoRange)
            {
                if (!UpdateAutoRange())
                    return;
            }
            UpdateCurveShow();
        }

        private bool UpdateAutoRange()
        {
            double min, max;

            if (!_curveGroup.GetCurveXRange(out min, out max))
                return false;
            _axis.XRange = new DoubleRange(min, max);

            if (!_curveGroup.GetCurveYRange(out min, out max))
                return false;
            _axis.YRange = new DoubleRange(min, max);

            return true;
        }

        private void _curveGroup_OnResize()
        {
            UpdateCursorShow((int)((_curveGroup.CursorXValue - _axis.XRange.Min) / _axis.XRange.Range * _curveGroup.Width + _curveGroup.Left));
        }

        private void _axis_OnUpdateXStartOffset(int offset)
        {
            _curveGroup.Resize(offset, 10, base.Width - offset, base.Height - _axis.ForeFont.Height - 10);
        }

        private void UpdateCursorShow(int x)
        {
            UpdateCursor(x);
            this.Refresh();
        }

        private void UpdateCurveShow()
        {
            _curveGroup.UpdateShow(_axis.XRange, _axis.YRange);

            this.Refresh();
        }

        private void UpdateCursor(int x)
        {
            x = CommonMath.Nearest(x, _curveGroup.Left, _curveGroup.Left + _curveGroup.Width - 1);

            _curveGroup.CursorXPoint = x;
            _curveGroup.CursorXValue = _axis.XRange.Range * (_curveGroup.CursorXPoint - _curveGroup.Left) / _curveGroup.Width + _axis.XRange.Min;

            double yValue;
            foreach (WaveCurve wave in _curveGroup.CurrentWaveList)
            {
                if (wave.GetYValue(_curveGroup.Smooth,_curveGroup.CursorXValue, out yValue))
                {
                    wave.CursorDescribe = string.Format("{0}:({1},{2})", wave.Name, _curveGroup.CursorXValue.ToString(_axis.ValueFormat), yValue.ToString(_axis.ValueFormat));

                    wave.XPoint = CommonMath.Nearest(_curveGroup.CursorXPoint, _curveGroup.Left, _curveGroup.Left + _curveGroup.Width - GetStringWidth(wave.CursorDescribe));
                    wave.YPoint =  _curveGroup.Top + CommonMath.Nearest((int)((_axis.YRange.Max - _axis.YRange.Nearest(yValue)) / _axis.YRange.Range * _curveGroup.Height), 0, _curveGroup.Height - wave.TextFont.Height);
                }
                else
                {
                    wave.CursorDescribe = string.Empty;
                }
            }
        }

        private int GetStringWidth(string str)
        {
            using (Graphics g = Graphics.FromHwnd(this.Handle))
            {
                return (int)Math.Round(g.MeasureString(str, base.Font).Width);
            }
        }

        private void WaveBox_Resize(object sender, EventArgs e)
        {
			if(base.Width <= 0)
				return;
		
            _axis.Resize(0, 10, base.Width, base.Height - 10);
            _curveGroup.Resize(_axis.XStartOffset, 10, base.Width - _axis.XStartOffset, base.Height - _axis.ForeFont.Height - 10);

            UpdateCurveShow();
        }

        private void WaveBox_Paint(object sender, PaintEventArgs e)
        {
            _axis.Paint(e.Graphics);
            _curveGroup.Paint(e.Graphics);
        }
    }

    /// <summary>
    /// 曲线坐标
    /// </summary>
    public class WaveAxis : CommonControl
    {
        string _xLabel, _yLabel;
        string _xMinValue, _xMaxValue, _yMinValue, _yMaxValue;
        string _valueFormat;
        int _xStartOffset;
        IntPtr _fatherHandle;
        DoubleRange _xRange, _yRange;

        public event IntInvoker OnUpdateXStartOffset;

        public int XStartOffset
        {
            get { return _xStartOffset; }
        }

        public string ValueFormat
        {
            set { _valueFormat = value; }
            get { return _valueFormat; }
        }

        public DoubleRange XRange
        {
            set
            {
                _xRange = value;

                UpdateXRange();
            }
            get
            {
                return _xRange;
            }
        }

        public DoubleRange YRange
        {
            set
            {
                _yRange = value;

                _yMinValue = value.Min.ToString(_valueFormat);
                _yMaxValue = value.Max.ToString(_valueFormat);

                _xStartOffset = Math.Max(Math.Max(GetStringWidth(_yMinValue), GetStringWidth(_yMaxValue)),GetStringWidth(_yLabel));

                if (OnUpdateXStartOffset != null)
                {
                    OnUpdateXStartOffset(_xStartOffset);
                }
            }
            get
            {
                return _yRange;
            }
        }

        public string XLabel
        {
            set { _xLabel = value; }
        }

        public string YLabel
        {
            set
            {
                _yLabel = value;

                _xStartOffset = Math.Max(Math.Max(GetStringWidth(_yMinValue), GetStringWidth(_yMaxValue)), GetStringWidth(value));

                if (OnUpdateXStartOffset != null)
                {
                    OnUpdateXStartOffset(_xStartOffset);
                }
            }
        }

        public WaveAxis(IntPtr fatherHandle)
        {
            _fatherHandle = fatherHandle;
            _xLabel = "X";
            _yLabel = "Y";
            _valueFormat = "f3";
            _xStartOffset = 0;
            base.ForeFont = new Font("Arial", 9);
            base.ForeBrush = SystemBrushes.FromSystemColor(SystemColors.Info);
            this.XRange = this.YRange = new DoubleRange(0,1);
        }

        public void UpdateXRange()
        {
            _xMinValue = _xRange.Min.ToString(_valueFormat);
            _xMaxValue = _xRange.Max.ToString(_valueFormat);
        }

        private int GetStringWidth(string str)
        {
            using (Graphics g = Graphics.FromHwnd(_fatherHandle))
            {
                return (int)Math.Round(g.MeasureString(str, base.ForeFont).Width);
            }
        }

        /// <summary>
        /// 显示
        /// </summary>
        /// <param name="graphic"></param>
        public void Paint(Graphics graphic)
        {
            if (base.Width <= _xStartOffset || base.Height <= base.ForeFont.Height * 4)
                return;

            int yOffset = base.Height - base.ForeFont.Height + base.Top;

            // X轴刻度值
            graphic.DrawString(_xMinValue, base.ForeFont, base.ForeBrush, _xStartOffset, yOffset);
            graphic.DrawString(_xMaxValue, base.ForeFont, base.ForeBrush, base.Width - GetStringWidth(_xMaxValue), yOffset);
            // X轴
            graphic.DrawLine(base.ForePen, base.Left + _xStartOffset, yOffset, base.Width - 1, yOffset);
            // X标签
            graphic.DrawString(_xLabel, base.ForeFont, base.ForeBrush, _xStartOffset + (base.Width - _xStartOffset) >> 1, yOffset);

            // Y轴刻度值
            graphic.DrawString(_yMaxValue, base.ForeFont, base.ForeBrush, base.Left, base.Top);
            graphic.DrawString(_yMinValue, base.ForeFont, base.ForeBrush, base.Left, base.Height + base.Top - (base.ForeFont.Height << 1));
            // Y轴
            graphic.DrawLine(base.ForePen, base.Left + _xStartOffset, base.Top, base.Left + _xStartOffset, yOffset);
            // Y标签
            graphic.DrawString(_yLabel, base.ForeFont, base.ForeBrush, 0, (((yOffset >> 1) - base.ForeFont.Height)));

            // Y轴O点
            if (_yRange.Min < 0 && _yRange.Max > 0)
            {
                int y = (int)Math.Round((base.Height - base.ForeFont.Height) * _yRange.Max / (_yRange.Max - _yRange.Min) + base.Top);

                graphic.DrawLine(base.ForePen, base.Left + _xStartOffset, y, base.Width - 1, y);
                graphic.DrawString("0", base.ForeFont, base.ForeBrush, _xStartOffset - GetStringWidth("0 "), y - (base.ForeFont.Height >> 1));
            }
        }
    }

    /// <summary>
    /// 曲线图组
    /// </summary>
    public class WaveCurveGroup : CommonControl
    {
        List<WaveCurve> _waveList;
        int _xPoint;
        double _xValue;
        bool _smooth;
        const double _precisionConstant = 0.001;

        public bool Smooth
        {
            get { return _smooth; }
            set { _smooth = value; }
        }

        public WaveCurve this[int index]
        {
            get
            {
                return _waveList[index];
            }
        }

        public int CursorXPoint
        {
            get { return _xPoint; }
            set
            {
                if (value < this.Left || value >= (this.Left + this.Width))
                    return;

                _xPoint = value;
            }
        }

        public double CursorXValue
        {
            get { return _xValue; }
            set { _xValue = value; }
        }

        public WaveCurve[] CurrentWaveList
        {
            get { return _waveList.ToArray(); }
        }

        public WaveCurveGroup()
        {
            _waveList = new List<WaveCurve>();
        }

        /// <summary>
        /// 可视曲线X轴最大最小值
        /// </summary>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public bool GetCurveXRange(out double min,out double max)
        {
            min = double.MaxValue;
            max = double.MinValue;

            foreach (WaveCurve wave in _waveList)
            {
                if (wave.Visible)
                {
                    if (wave.XRange.Min < min)
                        min = wave.XRange.Min;
                    if (wave.XRange.Max > max)
                        max = wave.XRange.Max;
                }
            }

            if(max <= min)
                return false;

            if (max - min <= _precisionConstant)
            {
                min = min - 0.5;
                max = max + 0.5;
            }
            return true;
        }

        /// <summary>
        /// 可视曲线Y轴最大最小值
        /// </summary>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public bool GetCurveYRange(out double min, out double max)
        {
            min = double.MaxValue;
            max = double.MinValue;

            foreach (WaveCurve wave in _waveList)
            {
                if (wave.Visible)
                {
                    if (wave.YRange.Min < min)
                        min = wave.YRange.Min;
                    if (wave.YRange.Max > max)
                        max = wave.YRange.Max;
                }
            }

            if (max <= min)
                return false;

            if (max - min <= _precisionConstant)
            {
                min = min - 0.5;
                max = max + 0.5;
            }
            return true;
        }

        public WaveCurve[] GenWaveArray(int waveCount)
        {
            if (waveCount <= 0)
                return null;

            WaveCurve[] waveArray = new WaveCurve[waveCount];
            for (int i = 0; i < waveCount; i++)
            {
                waveArray[i] = new WaveCurve();
                waveArray[i].Name = string.Format("CH{0}",i + _waveList.Count);
            }
            _waveList.AddRange(waveArray);

            return waveArray;
        }

        public void Clear()
        {
            _waveList.Clear();
        }

        /// <summary>
        /// 显示
        /// </summary>
        /// <param name="graphic"></param>
        public void Paint(Graphics graphic)
        {
            // 曲线显示及当前Y值指示
            foreach (WaveCurve wave in _waveList)
            {
                wave.Paint(graphic);
            }

            // X轴当前位置指示
            graphic.DrawLine(base.ForePen, _xPoint, base.Top, _xPoint, base.Top + base.Height);
        }

        public void UpdateShow(DoubleRange xAxisRange, DoubleRange yAxisRange)
        {
            int dataIndex,dataIndexStart, dataIndexEnd;
            int xPointIndex,xPointIndexStart,xPointIndexEnd,lastDataIndex;
            int minIndex, maxIndex;
            double min, max, tempData;
            int ymin, ymax;

            DoubleRange waveXAxisRange = new DoubleRange();
            Point p = new Point();
            LinePoints oPoints = new LinePoints();

            double yScale = this.Height / yAxisRange.Range;
            double yOffset = yAxisRange.Max * yScale + this.Top;
			double xAxisStep = this.Width / xAxisRange.Range;
			double dataStep,dataOff;
            foreach (WaveCurve wave in _waveList)
            {
                if (wave.Data == null || wave.Data.Length == 0)
                    continue;

                Debug.Assert(wave.Step > 0, "step应大于0");
                if (wave.Step <= 0)
                    continue;

                if (!xAxisRange.Contain(wave.XRange))
                    continue;

                waveXAxisRange.Min = Math.Max(xAxisRange.Min, wave.XRange.Min);
                waveXAxisRange.Max = Math.Min(xAxisRange.Max, wave.XRange.Max);

                dataOff = (waveXAxisRange.Min - wave.XRange.Min) * wave.Step;
                dataStep = wave.Step / xAxisStep;
                dataIndexEnd = (int)dataOff;

                xPointIndexStart = this.Left + (int)((waveXAxisRange.Min - xAxisRange.Min) * xAxisStep);
                xPointIndexEnd = this.Left + (int)((waveXAxisRange.Max - xAxisRange.Min) * xAxisStep);

                lastDataIndex = -1;
                oPoints.Begin();
                for (xPointIndex = xPointIndexStart; xPointIndex <= xPointIndexEnd; xPointIndex++)
                {
                    dataIndexStart = dataIndexEnd;
                    dataIndexEnd = (int)((xPointIndex - xPointIndexStart + 1) * dataStep + dataOff);
                    if (dataIndexEnd >= wave.Data.Length)
                    {
                        dataIndexEnd = wave.Data.Length - 1;
                    }

                    p.X = xPointIndex;
                    if (dataIndexStart < dataIndexEnd - 1)
                    {
                        // 计算范围内的最小最大值及其下标
                        min = max = wave.Data[dataIndexStart];
                        minIndex = maxIndex = dataIndexStart;
                        for (dataIndex = dataIndexStart; dataIndex < dataIndexEnd; dataIndex++)
                        {
                            tempData = wave.Data[dataIndex];
                            if (tempData < min)
                            {
                                minIndex = dataIndex;
                                min = tempData;
                            }
                            if (tempData > max)
                            {
                                maxIndex = dataIndex;
                                max = tempData;
                            }
                        }

                        // 存储采样波形结果
                        if (minIndex > maxIndex)
                        {
                            tempData = max;
                            max = min;
                            min = tempData;
                        }

                        ymin = GetNearestYPoint((yOffset - min * yScale));
                        ymax = GetNearestYPoint((yOffset - max * yScale));

                        p.Y = ymin;
                        oPoints.Add(p);

                        if (ymax != ymin)
                        {
                            p.Y = ymax;
                            oPoints.Add(p);
                        }

                        if (_smooth)
                        {
                            lastDataIndex = maxIndex;
                        }
                    }
                    else
                    {
                        max = 0;
                        if (_smooth)
                        {
                            if (lastDataIndex == dataIndexStart && xPointIndex != xPointIndexEnd)
                            {
                                continue;
                            }

                            if (dataIndexStart < wave.Data.Length - 1)
                            {
                                if (xPointIndex == xPointIndexStart)
                                {
                                    max = (wave.Data[dataIndexStart + 1] - wave.Data[dataIndexStart]) * (dataOff - dataIndexStart) + wave.Data[dataIndexStart];
                                }
                                else if (xPointIndex == xPointIndexEnd)
                                {
                                    max = (wave.Data[dataIndexStart + 1] - wave.Data[dataIndexStart]) * ((xPointIndexEnd - xPointIndexStart) * dataStep + dataOff - dataIndexStart) + wave.Data[dataIndexStart];
                                }
                                else
                                {
                                    max = wave.Data[dataIndexStart];
                                }
                            }
                            else
                            {
                                max = wave.Data[dataIndexStart];
                            }
                            lastDataIndex = dataIndexStart;
                        }
                        else
                        {
                            max = wave.Data[dataIndexStart];
                        }

                        p.Y = GetNearestYPoint((yOffset - max * yScale));
                        oPoints.Add(p);
                    }
                }

                oPoints.End();
                wave.Points = oPoints.Points;
            }
        }

        private int GetNearestYPoint(double yPoint)
        {
            return CommonMath.Nearest((int)Math.Round(yPoint), base.Top, base.Top + base.Height);
        }
    }

    /// <summary>
    /// 曲线图
    /// </summary>
    public class WaveCurve
    {
        bool _visible;
        double[] _data;
        double _step;
        Pen _linePen;
        Brush _textBrush;
        Font _textFont;
        Point[] _points;
        string _name;
        int _xPoint, _yPoint;
        string _cursorDescribe;
        DoubleRange _xRange,_yRange;

        public int XPoint
        {
            set { _xPoint = value; }
        }

        public int YPoint
        {
            set { _yPoint = value; }
        }

        public string CursorDescribe
        {
            set { _cursorDescribe = value; }
            get { return _cursorDescribe; }
        }

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public Pen LinePen
        {
            set { _linePen = value; }
        }

        public Brush TextBrush
        {
            set { _textBrush = value; }
        }

        public Font TextFont
        {
            get { return _textFont; }
            set { _textFont = value; }
        }

        public Point[] Points
        {
            set { _points = value; }
        }

        public bool Visible
        {
            get { return _visible; }
            set { _visible = value; }
        }

        public double[] Data
        {
            get { return _data; }
        }

        public double Step
        {
            get { return _step; }
        }

        public DoubleRange XRange
        {
            get { return _xRange; }
        }

        public DoubleRange YRange
        {
            get { return _yRange; }
        }

        public WaveCurve()
        {
            _visible = true;
            _linePen = Pens.Blue;
            _points = null;
            _textFont = new Font("Arial", 9);
            _textBrush = Brushes.Blue;
            _xRange = _yRange = DoubleRange.Empty;
        }

        /// <summary>
        /// 显示
        /// </summary>
        /// <param name="graphic"></param>
        public void Paint(Graphics graphic)
        {
            if (!_visible || _points == null || _points.Length <= 0)
                return;

            graphic.DrawLines(_linePen, _points);

            if (!string.IsNullOrEmpty(_cursorDescribe))
            {
                graphic.DrawString(_cursorDescribe, _textFont, _textBrush, _xPoint, _yPoint);
            }
        }

        public void UpdateData(double[] xData,DoubleRange xRange)
        {
            if (xData == null || xData.Length == 0 || !xRange.IsGood)
                return;

            _data = (double[])xData.Clone();
            _xRange = xRange;
            _yRange = DoubleRange.GetRange(xData);

            _step = xData.Length / xRange.Range;
        }

        public bool GetYValue(bool smooth,double xValue,out double yValue)
        {
            if (_xRange == null || !_xRange.Contain(xValue) || _data == null || _data.Length < 2)
            {
                yValue = 0;
                return false;
            }

            if (smooth)
            {
                yValue = _data[(int)Math.Round(((xValue - _xRange.Min) / _xRange.Range) * _data.Length)];
            }
            else
            {
                yValue = _data[(int)(((xValue - _xRange.Min) / _xRange.Range) * _data.Length)];
            }
            return true;
        }
    }
}
